package com.itkjb.leisurely.resource.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itkjb.leisurely.core.base.BaseConstants;
import com.itkjb.leisurely.core.base.service.impl.BaseServiceImpl;
import com.itkjb.leisurely.core.exception.LeisurelyException;
import com.itkjb.leisurely.core.util.RedisUtil;
import com.itkjb.leisurely.core.util.TreeUtils;
import com.itkjb.leisurely.resource.common.SysConstants;
import com.itkjb.leisurely.resource.sys.mapper.SysDepartmentMapper;
import com.itkjb.leisurely.resource.sys.model.SysDepartmentModel;
import com.itkjb.leisurely.resource.sys.model.vo.SysDepartmentVO;
import com.itkjb.leisurely.resource.sys.service.ISysDepartmentService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 * 组织结构 服务实现类
 * </p>
 *
 * @author itkjb.com
 * @since 2020-07-02
 */
@Service
public class SysDepartmentServiceImpl extends BaseServiceImpl<SysDepartmentMapper, SysDepartmentModel> implements ISysDepartmentService {

    @Autowired(required = false)
    RedisUtil redisUtil;

    private ReentrantLock lock = new ReentrantLock();
    private static final String TREE_LIST_KEY = SysConstants.SYS_PREFIX + SysConstants.DEPARTMENT_KEY + "tree_list";
    private static final String TREE_MAP_KEY = SysConstants.SYS_PREFIX + SysConstants.DEPARTMENT_KEY + "tree_map";
    private static final String SUB_IDS_KEY = SysConstants.SYS_PREFIX + SysConstants.DEPARTMENT_KEY + "sub_ids";

    /**
     * 新增
     * 为了在新增时，更新 上级 的下级数量，update sub_count 的数量，重写save 方法
     *
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(SysDepartmentModel entity) {
        SysDepartmentModel parentModel = getParentModel(entity.getParentId());
        entity.setLevel(parentModel.getLevel() + 1);
        entity.setParentName(parentModel.getDepName());
        if (super.save(entity)) {
            // 保存完，清除缓存
            clearCatch();
            return updateSubCount(entity.getParentId(), true);
        } else {
            return false;
        }
    }

    /**
     * 更新
     * 为了在更新时，更新 上级 的下级数量，update sub_count 的数量，重写updateById方法
     *
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(SysDepartmentModel entity) {
        SysDepartmentModel old = this.getById(entity.getId());
        if (old == null) {
            return false;
        }
        SysDepartmentModel parentModel = getParentModel(entity.getParentId());
        entity.setLevel(parentModel.getLevel() + 1);
        entity.setParentName(parentModel.getDepName());
        Serializable newParentId = SysConstants.DEFAULT_TOP_PARENT_ID;
        Serializable oldParentId = SysConstants.DEFAULT_TOP_PARENT_ID;
        if (entity.getParentId() != null && !entity.getParentId().equals(old.getParentId())) {
            newParentId = entity.getParentId();
            oldParentId = old.getParentId();
        }
        if (super.updateById(entity)) {
            // 更新完，清除缓存
            clearCatch();
            updateSubCount(newParentId, true);
            updateSubCount(oldParentId, false);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取上级部门信息
     *
     * @param parentId
     * @return
     */
    private SysDepartmentModel getParentModel(String parentId) {
        SysDepartmentModel model;
        if (StringUtils.isBlank(parentId) || BaseConstants.DEFAULT_TOP_PARENT_ID.equals(parentId)) {
            model = new SysDepartmentModel();
            model.setParentId(BaseConstants.DEFAULT_TOP_PARENT_ID);
            model.setLevel(0);
        } else {
            model = this.getById(parentId);
            if (model == null) {
                throw new LeisurelyException("未找到指定上级");
            } else if (model.getLevel() == null) {
                model.setLevel(0);
            }
        }
        return model;
    }

    /**
     * 为了在删除时 更新 下级数量 sub_count 的值，从写了删除方法
     *
     * @param idList
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        // 这里为了避免多操作和线程间的感染，采用了单机锁，实际过程中建议采用redis 分布式锁
        lock.lock();
        try {
            updateSubCountForDelete(idList);
            boolean b = super.removeByIds(idList);
            if (b) {
                // 删除完，清除缓存
                clearCatch();
            }
            return b;
        } catch (Exception e) {
            throw e;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 删除时，更新sub_count 数量
     *
     * @param ids
     * @return
     */
    protected boolean updateSubCountForDelete(Collection<? extends Serializable> ids) {
        QueryWrapper<SysDepartmentModel> wrapper = new QueryWrapper<>();
        wrapper = wrapper.select("id", "parent_id").in("id", ids);
        List<SysDepartmentModel> list = this.list(wrapper);
        Map<Serializable, Integer> toUpIds = new HashMap<>();
        if (list != null && list.size() > 0) {
            list.forEach(model -> {
                if (model.getParentId() != null
                        && StringUtils.isNotBlank(model.getParentId())
                        && !BaseConstants.DEFAULT_TOP_PARENT_ID.equals(model.getParentId())) {
                    toUpIds.put(model.getParentId(), toUpIds.get(model.getParentId()) == null ? 1 : toUpIds.get(model.getParentId()) + 1);
                }
            });
        }
        updateSubCountByMapForDel(toUpIds);
        return true;
    }

    /**
     * tree 组装树
     *
     * @param id 指定id,下的所有树
     * @return
     */
    @Override
    public List<SysDepartmentVO> tree(String id) {
        if (StringUtils.isBlank(id)) {
            return tree();
        } else {
            if (!redisUtil.hasKey(TREE_MAP_KEY)) {
                disassembleTreeToRedis(tree(), null);
            }
            return (List<SysDepartmentVO>) redisUtil.hget(TREE_MAP_KEY, id);
        }
    }

    /**
     * 拆解树
     *
     * @return
     */
    protected void disassembleTreeToRedis(List<SysDepartmentVO> tree, SysDepartmentVO parent) {
        if (tree == null || tree.size() <= 0) {
            return;
        } else {
            if (parent == null) {
                redisUtil.hset(TREE_MAP_KEY, tree.get(0).getParentId(), tree, SysConstants.TIME_120_SECOND);
            } else {
                List<SysDepartmentVO> newTree = new ArrayList<>();
                newTree.add(parent);
                parent.setChildren(tree);
                redisUtil.hset(TREE_MAP_KEY, parent.getId(), newTree, SysConstants.TIME_120_SECOND);
            }

            tree.forEach(sysDepartmentVO -> {
                if (sysDepartmentVO.getChildren() != null && sysDepartmentVO.getChildren().size() > 0) {
                    disassembleTreeToRedis(sysDepartmentVO.getChildren(), sysDepartmentVO);
                }
            });
        }
    }

    @Override
    public List<SysDepartmentVO> tree() {
        List<SysDepartmentVO> treeList; // 完整的组织结构树
        treeList = redisUtil.lGet(TREE_LIST_KEY, 0, -1);
        if (treeList == null || treeList.size() <= 0) {
            QueryWrapper<SysDepartmentModel> wrapper = new QueryWrapper<>();
            // 构建查询字段
            wrapper.lambda().select(SysDepartmentModel::getId,
                    SysDepartmentModel::getDepName,
                    SysDepartmentModel::getParentId, SysDepartmentModel::getPaixu);
            wrapper.lambda().eq(SysDepartmentModel::getStatus, 1);
            wrapper.lambda().eq(SysDepartmentModel::getIsDel, false);
            List<SysDepartmentModel> sysDepartmentModels = this.baseMapper.selectList(wrapper);
            List<SysDepartmentVO> vos = new ArrayList<>();
            treeList = sysDepartmentModel2VOTree(sysDepartmentModels,vos);
            redisUtil.lSetListForReset(TREE_LIST_KEY, treeList, SysConstants.TIME_120_SECOND);
        }
        return treeList;

    }

    /**
     * 根据指定的depIds组装数
     * @param model
     * @return
     */
    @Override
    public List<SysDepartmentVO> tree(SysDepartmentModel model) {
        List<SysDepartmentVO> treeList;  // 指定的组织结构树
        QueryWrapper<SysDepartmentModel> wrapper = new QueryWrapper<>();
        // 构建查询字段
        wrapper.lambda().select(SysDepartmentModel::getId,
                SysDepartmentModel::getDepName,
                SysDepartmentModel::getParentId, SysDepartmentModel::getPaixu);
        // 查询指定的组部门
        model.setStatus(1);
        assembleWrapper(wrapper,model);
        wrapper.lambda().eq(SysDepartmentModel::getIsDel, false);
//        wrapper.lambda().in(model.get_depIds() != null && model.get_depIds().size()>0,
//                SysDepartmentModel::getId, model.get_depIds());
        List<SysDepartmentModel> sysDepartmentModels = this.baseMapper.selectList(wrapper);
        List<SysDepartmentVO> vos = new ArrayList<>();
        treeList = sysDepartmentModel2VOTree(sysDepartmentModels,vos);
        return treeList;

    }
    protected List<SysDepartmentVO> sysDepartmentModel2VOTree( List<SysDepartmentModel> sysDepartmentModels,List<SysDepartmentVO> vos){
        List<SysDepartmentVO> treeList;
        for (SysDepartmentModel sysMenuModel : sysDepartmentModels) {
            SysDepartmentVO vo = new SysDepartmentVO();
            BeanUtils.copyProperties(sysMenuModel, vo);
            vos.add(vo);
        }
        sysDepartmentModels = null; // 提前释放内存
        TreeUtils<SysDepartmentVO> treeUtils = new TreeUtils<>();
        treeList = treeUtils.tree(vos);
        return treeList;
    }
    /**
     * 返回指定节点下，所有子节点的Id(不包括自身)
     *
     * @param id
     * @return
     */
    @Override
    public Set<String> getSubIds(String id) {
        Set<String> vlist = null;
        Map<String, Set<String>> subIdSMap = redisUtil.hmget(SUB_IDS_KEY);
        if (subIdSMap == null || subIdSMap.size() <= 0) {
            List<SysDepartmentVO> treeList = tree();
            TreeUtils<SysDepartmentVO> treeUtils = new TreeUtils<>();
            subIdSMap = treeUtils.getSubIds(treeList, SysConstants.DEFAULT_TOP_PARENT_ID);
            redisUtil.hmset(SUB_IDS_KEY, subIdSMap, SysConstants.TIME_120_SECOND * 2);
        }
        vlist = subIdSMap.get(id);
        return vlist;
    }

    @Override
    public Set<String> getIdAndSubIds(String id) {
        Set<String> subIds = getSubIds(id);
        if (subIds != null) {
            subIds.add(id);
        } else {
            subIds = new HashSet<>();
            subIds.add(id);
        }
        return subIds;
    }

    @Override
    public List<SysDepartmentModel> findUserDepsByUserId(String userId) {
        return this.baseMapper.findUserDepsByUserId(userId);
    }

    /**
     * wrapper 组装器，构造条件查询
     *
     * @param wrapper
     * @param model   条件
     * @author itkjb.com
     * @date 2020-07-02
     **/
    @Override
    protected void assembleWrapper(QueryWrapper<SysDepartmentModel> wrapper, SysDepartmentModel model) {
        if(model == null){
            return ;
        }
        wrapper.lambda().eq(StringUtils.isNotBlank(model.getId()), SysDepartmentModel::getId, model.getId());
        // 组织名字
        wrapper.lambda().eq(StringUtils.isNotBlank(model.getDepName()), SysDepartmentModel::getDepName, model.getDepName());
        // 组织机构代码
        wrapper.lambda().eq(StringUtils.isNotBlank(model.getDepCode()), SysDepartmentModel::getDepCode, model.getDepCode());
        // 父级id
        wrapper.lambda().eq(StringUtils.isNotBlank(model.getParentId()), SysDepartmentModel::getParentId, model.getParentId());
        // 顶级组织id
        wrapper.lambda().eq(StringUtils.isNotBlank(model.getTopId()), SysDepartmentModel::getTopId, model.getTopId());
        // 组织结构级别 默认都是第一级，每往下一级加1
        wrapper.lambda().eq(model.getLevel() != null, SysDepartmentModel::getLevel, model.getLevel());
        // 状态  1可用 ：0 禁用
        wrapper.lambda().eq(model.getStatus() != null, SysDepartmentModel::getStatus, model.getStatus());

        wrapper.lambda().in(model.get_depIds() != null && model.get_depIds().size()>0,
                SysDepartmentModel::getId, model.get_depIds());

    }

    /**
     * wrapper 组装器，组装list查询时，查询的列
     *
     * @param wrapper
     * @param model
     * @return void
     * @author itkjb.com
     * @date 2020-07-02
     * @since 2020-07-02
     **/
    @Override
    protected void buildListSelectColumns(QueryWrapper<SysDepartmentModel> wrapper, SysDepartmentModel model) {
        buildCommonSelectColumns(wrapper, model);
    }

    /**
     * 组装列表查询的列（字段）
     *
     * @param wrapper
     * @param model
     * @date 2020-07-02
     */
    protected void buildCommonSelectColumns(QueryWrapper<SysDepartmentModel> wrapper, SysDepartmentModel model) {
        wrapper.lambda().select(
                // id
                SysDepartmentModel::getId,
                // 组织名字
                SysDepartmentModel::getDepName,
                // 组织机构代码
                SysDepartmentModel::getDepCode,
                // 父级id
                SysDepartmentModel::getParentId,
                // 父级名字
                SysDepartmentModel::getParentName,
                // 拥有的子节点数量
                SysDepartmentModel::getSubCount,
                // 顶级组织id
                SysDepartmentModel::getTopId,
                // 组织结构级别 默认都是第一级，每往下一级加1
                SysDepartmentModel::getLevel,
                // 组织的logo
//            SysDepartmentModel::getLogo,
                // 负责人
                SysDepartmentModel::getPrincipal,
                // 联系电话
                SysDepartmentModel::getLinkPhone,
//            // 省id
//            SysDepartmentModel::getProvinceId,
//            // 市id
//            SysDepartmentModel::getCityId,
//            // 县id
//            SysDepartmentModel::getCountyId,
//            // 县级以上名字 ，中间用-分割
//            SysDepartmentModel::getCountyName,
//            // 详细地址
//            SysDepartmentModel::getDepAddress,
//            // 组织描述
//            SysDepartmentModel::getDescription,
                // 状态  1可用 ：0 禁用
                SysDepartmentModel::getStatus,
                // 排序，也可当级别用
                SysDepartmentModel::getPaixu,
                // 备注
//            SysDepartmentModel::getRemark,
                SysDepartmentModel::getCreateTime
        );
    }

    /**
     * 清除缓存
     */
    protected void clearCatch() {
        redisUtil.del(TREE_LIST_KEY, TREE_MAP_KEY, SUB_IDS_KEY);
    }
}
